package org.qiyu.live.user.provider.service.impl;

import com.alibaba.fastjson.JSON;
import jakarta.annotation.Resource;
import org.apache.rocketmq.client.producer.MQProducer;
import org.apache.rocketmq.common.message.Message;
import org.idea.qiyu.live.framework.redis.starter.key.UserProviderCacheKeyBuilder;
import org.qiyu.live.common.interfaces.utils.ConvertBeanUtils;
import org.qiyu.live.user.constants.UserTagFieldNameConstants;
import org.qiyu.live.user.constants.UserTagsEnum;
import org.qiyu.live.user.dto.UserCacheAsyncDeleteDTO;
import org.qiyu.live.user.dto.UserTagDTO;
import org.qiyu.live.user.provider.dao.mapper.IUserTagMapper;
import org.qiyu.live.user.provider.dao.po.UserTagPO;
import org.qiyu.live.user.provider.service.IUserTagService;
import org.qiyu.live.user.utils.TagInfoUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.qiyu.live.user.constants.UserProviderTopicNames.CHANGE_TOPIC;

/**
 * @Author ideak
 * @Date: Created in 17:13 2025/4/6
 * @Description
 */
@Service
public class UserTagServiceImpl implements IUserTagService {

    @Resource
    private IUserTagMapper userTagMapper;

//    @Resource
//    private RedisTemplate<String,String> redisTemplate;

    @Resource
    private RedisTemplate<String, UserTagDTO> redisTemplate;

    @Resource
    private UserProviderCacheKeyBuilder cacheKeyBuilder;

    @Resource
    private MQProducer mqProducer;

    /**
     * 给用户设置标签
     * @param userId
     * @param userTagsEnum
     * @return
     */
    @Override
    public boolean setTag(Long userId, UserTagsEnum userTagsEnum) {
        boolean b = userTagMapper.setTag(userId, userTagsEnum.getFieldName(), userTagsEnum.getTag()) > 0;
        if(b){
            //清理缓存
            delTagRedis(userId);
            return true;
        }
        UserTagPO userTagPO = userTagMapper.selectById(userId);
        if(userTagPO != null){
            return false;
        }

        String key = cacheKeyBuilder.buildTagLockKey(userId);
        String set = (String) redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                //序列化
                RedisSerializer keySerializer = redisTemplate.getKeySerializer();
                RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
                //设置标签的同时设置超时时间，原子化
                String set = (String) connection.execute("set", keySerializer.serialize(key),
                        valueSerializer.serialize("-1"), "NX".getBytes(StandardCharsets.UTF_8),
                        "EX".getBytes(StandardCharsets.UTF_8), "3".getBytes(StandardCharsets.UTF_8));
                return set;
            }
        });

        if(!"OK".equals(set)){
            return false;
        }

        UserTagPO userTagPO1 = new UserTagPO();
        userTagPO1.setUserId(userId);
        userTagMapper.insert(userTagPO1);
        redisTemplate.delete(key);
        return true;
    }

    /**
     * 取消标签
     * @param userId
     * @param userTagsEnum
     * @return
     */
    @Override
    public boolean cancelTag(Long userId, UserTagsEnum userTagsEnum) {
        boolean b = userTagMapper.cancelTag(userId, userTagsEnum.getFieldName(), userTagsEnum.getTag()) > 0;
        if(!b){
            return false;
        }
        //删除成功需要清理缓存
        delTagRedis(userId);
        return true;
    }

    /**
     * 判断标签是否存在
     * @param userId
     * @param userTagsEnum
     * @return
     */
    @Override
    public boolean containTag(Long userId, UserTagsEnum userTagsEnum) {
        //获取用户标签，通过缓存获取
        UserTagDTO userTagDTO = this.queryByUserIdFromRedis(userId);
        if (userTagDTO == null) {
            return false;
        }
        String queryFieldName = userTagsEnum.getFieldName();
        if (UserTagFieldNameConstants.TAG_INFO_01.equals(queryFieldName)) {
            return TagInfoUtils.isContain(userTagDTO.getTagInfo01(), userTagsEnum.getTag());
        } else if (UserTagFieldNameConstants.TAG_INFO_02.equals(queryFieldName)) {
            return TagInfoUtils.isContain(userTagDTO.getTagInfo02(), userTagsEnum.getTag());
        } else if (UserTagFieldNameConstants.TAG_INFO_03.equals(queryFieldName)) {
            return TagInfoUtils.isContain(userTagDTO.getTagInfo03(), userTagsEnum.getTag());
        }
        return false;
    }

    /**
     * 清理redis中的用户标签缓存
     * @param userId
     */
    public void delTagRedis(Long userId) {
        String key = cacheKeyBuilder.buildTagLockKey(userId);
        redisTemplate.delete(key);

        //删除缓存后延迟双删
        UserCacheAsyncDeleteDTO deleteDTO = new UserCacheAsyncDeleteDTO();
        deleteDTO.setCode(0);
        Map<String, String> jsonPram = new HashMap<>();
        jsonPram.put("userId", String.valueOf(userId));
        deleteDTO.setJson(JSON.toJSONString(jsonPram));
        Message message = new Message();
        message.setTopic(CHANGE_TOPIC);
        message.setBody(JSON.toJSONString(deleteDTO).getBytes());
        message.setDelayTimeLevel(1); //延迟一秒时间进行删除
        try {
            mqProducer.send(message);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    public UserTagDTO queryByUserIdFromRedis(Long userId) {
        String redisKey = cacheKeyBuilder.buildTagKey(userId);

        UserTagDTO userTagDTO = redisTemplate.opsForValue().get(redisKey);
        if(userTagDTO != null){
            return userTagDTO;
        }
        UserTagPO userTagPO = userTagMapper.selectById(userId);
        if(userTagPO == null){
            return null;
        }
        userTagDTO = ConvertBeanUtils.convert(userTagPO, UserTagDTO.class);
        //准备更新数据，从向redis存入数据
        redisTemplate.opsForValue().set(redisKey, userTagDTO);
        redisTemplate.expire(redisKey,30, TimeUnit.MINUTES);
        return userTagDTO;
    }

}
